package com.geek.javase.ch18.videodemo.reflect.singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*
 *@Date 2025/11/7
 *@Author wangpeng
 *@Description
 * 1.反射能够获取私有的构造方法，进行创建实例，与当前getInstance()获取的实例是同一个吗？
 * 答：不是同一个实例
 * 2.通过反射获取实例，是否能保证获取的是单实例？
 */

////1.反射能够获取私有的构造方法，进行创建实例，与当前getInstance()获取的实例是同一个吗？
//public class SingletonDemo2 {
//    //私有的 静态的 本类实例
//    //private static SingletonDemo2 instance;
//    private volatile static SingletonDemo2 instance;
//
//    //私有的构造方法
//    private SingletonDemo2() {
//        System.out.println(Thread.currentThread().getName());
//    }
//    //公开的 静态的 获得本类实例的方法
//    public static SingletonDemo2 getInstance() {
//        if (instance == null) {
//            synchronized (SingletonDemo2.class) {
//                if (instance == null) {
//                     /*
//                     * volatile 确保可见性、不能保证原子性、禁止指令重排
//                     * 1.创建实例
//                     * 2.为其分配内存空间
//                     * 3.将内存空间复制给实例对象
//                     * 期望：123   可能：132
//                     * 解决：加锁
//                     * */
//
//                    instance = new SingletonDemo2();
//                }
//            }
//        }
//        return instance;
//    }
//}
//class Test2{
//    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//        System.out.println("1.通过线程安全的单例模式 - 懒汉式 DCL(Double Check Lock) + volatile获取实例");
//        SingletonDemo2 s1 = SingletonDemo2.getInstance();
//        SingletonDemo2 s2 = SingletonDemo2.getInstance();
//        System.out.println(s1);
//        System.out.println(s2);
//        System.out.println(s1 == s2); //true
//
//        System.out.println("2.通过反射获取实例");
//        //通过反射获取私有构造器
//        Class<SingletonDemo2> clazz = SingletonDemo2.class;
//        Constructor<SingletonDemo2> declaredConstructor = clazz.getDeclaredConstructor();
//        //取消访问权限检查
//        declaredConstructor.setAccessible(true);
//        //创建实例
//        SingletonDemo2 s3  = declaredConstructor.newInstance();
//        System.out.println(s3);
//        System.out.println(s2==s3);  //false
//    }
//}


//2.通过反射获取实例，是否能保证获取的是单实例？ 没有更好的办法，但可以通过提示，禁止其再次构造！
public class SingletonDemo2 {
    //私有的 静态的 本类实例
    //private static SingletonDemo2 instance;
    private volatile static SingletonDemo2 instance;

    //私有的构造方法
    private SingletonDemo2() {
        synchronized (SingletonDemo2.class) {
            if (instance != null) {
                throw new IllegalArgumentException("该类已经有了实例，不可再进行构造！");
            }
        }
    }

    //公开的 静态的 获得本类实例的方法
    public static SingletonDemo2 getInstance() {
        if (instance == null) {
            synchronized (SingletonDemo2.class) {
                if (instance == null) {
                    /*
                     * volatile 确保可见性、不能保证原子性、禁止指令重排
                     * 1.创建实例
                     * 2.为其分配内存空间
                     * 3.将内存空间复制给实例对象
                     * 期望：123   可能：132
                     * 解决：加锁
                     * */
                    instance = new SingletonDemo2();
                }
            }
        }
        return instance;
    }
}

class Test2 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        System.out.println("1.通过线程安全的单例模式 - 懒汉式 DCL(Double Check Lock) + volatile获取实例");
        SingletonDemo2 s1 = SingletonDemo2.getInstance();
        SingletonDemo2 s2 = SingletonDemo2.getInstance();
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s1 == s2); //true

        System.out.println("2.通过反射获取实例");
        //通过反射获取私有构造器
        Class<SingletonDemo2> clazz = SingletonDemo2.class;
        Constructor<SingletonDemo2> declaredConstructor = clazz.getDeclaredConstructor();
        //取消访问权限检查
        declaredConstructor.setAccessible(true);
        //创建实例
        SingletonDemo2 s3 = declaredConstructor.newInstance();
        System.out.println(s3);
        System.out.println(s2 == s3);  //false
    }
}